﻿using Azure;
using LiveCharts;
using LiveCharts.Wpf;
using log4net;
using Sunny.UI;
using System.Diagnostics.CodeAnalysis;
using Excel = Microsoft.Office.Interop.Excel;

namespace FZRD

{
    public partial class Page2 : UIPage
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Page2));
        //X轴值数量初始值
        private long xCount = 1000;
        //X轴值最大计数值
        private long xTimes = 0;

        private long yCount = 0;
        //传感器选择位置
        private int sensorIndex = 0;

        private string waveFilePath = "D:\\聚芯光纤\\";

        private string waveFileName = "历史数据";

        private string waveFileNameDate = "";

        [DisallowNull]
        private Excel.Application excelApp;

        [DisallowNull]
        private Excel._Workbook workbook;

        private List<SensorDeviceData> sensorDeviceDataList = new List<SensorDeviceData>();

        private List<SensorEntity> sensorEntityList = new List<SensorEntity>();

        private Random R = new Random();//为了给Y值提供随机值


        public Page2()
        {
            InitializeComponent();
            InitChartConfig();
            #region  多Y轴曲线
            //将自定义类型MeasureModel映射到曲线坐标点
            var mapper = LiveCharts.Configurations.Mappers.Xy<DateTimePoint>()
              .X(model => model.Time)    //使用Time.作为X轴的标签
              .Y(model => model.Value);  //使用Value 作为Y轴的值
            //全局保存映射器
            Charting.For<DateTimePoint>(mapper);
            #endregion

            try
            {
                var sql = @"select * from sensor_table";
                var dt = MainForm.db.SelectDataTable(sql);

                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    var row = dt.Rows[i];
                    var sensorEntity = new SensorEntity()
                    {
                        ID = (int)row["ID"],
                        SensorName = row["SensorName"] != DBNull.Value ? row["SensorName"].ToString() : "",
                        SensorType = row["SensorType"] != DBNull.Value ? (int)row["SensorType"] : 0,
                        ChannelIndex = row["ChannelIndex"] != DBNull.Value ? (int)row["ChannelIndex"] : 0,
                        SensorIndex = row["SensorIndex"] != DBNull.Value ? (int)row["SensorIndex"] : 0,
                        WaveCount = row["WaveCount"] != DBNull.Value ? (int)row["WaveCount"] : 0,
                        Expression = row["Expression"] != DBNull.Value ? row["Expression"].ToString() : "",
                        Description = row["Description"] != DBNull.Value ? row["Description"].ToString() : "",
                        Param1 = row["Param1"] != DBNull.Value ? row["Param1"].ToString() : "",
                        Param2 = row["Param2"] != DBNull.Value ? row["Param2"].ToString() : "",
                        Param3 = row["Param3"] != DBNull.Value ? row["Param3"].ToString() : "",
                        Param4 = row["Param4"] != DBNull.Value ? row["Param4"].ToString() : "",
                        Param5 = row["Param5"] != DBNull.Value ? row["Param5"].ToString() : "",
                        Param6 = row["Param6"] != DBNull.Value ? row["Param6"].ToString() : "",
                        Param7 = row["Param7"] != DBNull.Value ? row["Param7"].ToString() : "",
                        Param8 = row["Param8"] != DBNull.Value ? row["Param8"].ToString() : "",
                        Param9 = row["Param9"] != DBNull.Value ? row["Param9"].ToString() : "",
                        Param10 = row["Param10"] != DBNull.Value ? row["Param10"].ToString() : "",
                        Param11 = row["Param11"] != DBNull.Value ? row["Param11"].ToString() : "",
                        Param12 = row["Param12"] != DBNull.Value ? row["Param12"].ToString() : "",
                        Param13 = row["Param13"] != DBNull.Value ? row["Param13"].ToString() : "",
                        Param14 = row["Param14"] != DBNull.Value ? row["Param14"].ToString() : "",
                        Param15 = row["Param15"] != DBNull.Value ? row["Param15"].ToString() : "",
                        Param16 = row["Param16"] != DBNull.Value ? row["Param16"].ToString() : ""
                    };
                    this.cbWaveSensorSellect.Items.Add(sensorEntity.SensorName);
                    sensorEntityList.Add(sensorEntity);
                }

                if (sensorEntityList.Count > 0)
                {
                    this.cbWaveSensorSellect.SelectedIndex = 0;
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }

        private ChartValues<DateTimePoint> InitChartValuesEmptyData()
        {
            ChartValues<DateTimePoint> chartValues = new ChartValues<DateTimePoint>();
            return chartValues;
        }

        private void btnQuery_Click(object sender, EventArgs e)
        {
            sensorIndex = cbWaveSensorSellect.SelectedIndex;
            DateTime startTime = startDatetime.Value;
            DateTime endTime = endDatetime.Value;
            QuerySqlData(sensorIndex, startTime, endTime);
            RecordUserOperation("历史记录查询 sensorIndex="+ sensorIndex + " startTime=" + startTime.ToString("yyyy-MM-dd HH:mm:ss") + " startTime=" + endTime.ToString("yyyy-MM-dd HH:mm:ss"));
        }
        public void QuerySqlData(int sensorIndex, DateTime startTime, DateTime endTime)
        {
            try
            {
                sensorDeviceDataList.Clear();
                SensorEntity sensorEntity = sensorEntityList.Get(sensorIndex);
                var sql = @"select * from sensor_device_data where 1=1 ";
                if (sensorEntity != null)
                {
                    sql = sql + @" and sensor_id=" + sensorEntity.ID;
                }
                sql = sql + @" and collect_time > " + ToUnixTimestampMilliseconds(startTime) + @" and collect_time < " + ToUnixTimestampMilliseconds(endTime) + @" order by collect_time limit " + this.xCount + @";";
                var dt = MainForm.db.SelectDataTable(sql);

                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    var row = dt.Rows[i];
                    var sensorDeviceData = new SensorDeviceData()
                    {
                        id = (long)row["id"],
                        uid = row["uid"] != DBNull.Value ? (string)(row["uid"]) : "",
                        device_id = row["device_id"] != DBNull.Value ? (string)row["device_id"] : "",
                        collect_time = row["collect_time"] != DBNull.Value ? (long)row["collect_time"] : 0,
                        collect_datetime = row["collect_datetime"] != DBNull.Value ? (string)row["collect_datetime"] : "",
                        channel_id = row["channel_id"] != DBNull.Value ? (int)row["channel_id"] : 0,
                        sensor_id = row["sensor_id"] != DBNull.Value ? (string)row["sensor_id"] : "",
                        sensor_name = row["sensor_name"] != DBNull.Value ? (string)row["sensor_name"] : "",
                        sensor_type = row["sensor_type"] != DBNull.Value ? (int)row["sensor_type"] : 0,
                        sensor_count = row["sensor_count"] != DBNull.Value ? (int)row["sensor_count"] : 0,
                        sensor_index = row["sensor_index"] != DBNull.Value ? (int)row["sensor_index"] : 0,
                        wave_length1 = row["wave_length1"] != DBNull.Value ? Convert.ToDouble(row["wave_length1"]) : 0.0,
                        wave_length2 = row["wave_length2"] != DBNull.Value ? Convert.ToDouble(row["wave_length2"]) : 0.0,
                        wave_length3 = row["wave_length3"] != DBNull.Value ? Convert.ToDouble(row["wave_length3"]) : 0.0,
                        count_value1 = row["count_value1"] != DBNull.Value ? Convert.ToDouble(row["count_value1"]) : 0.0,
                        count_value2 = row["count_value2"] != DBNull.Value ? Convert.ToDouble(row["count_value2"]) : 0.0,
                        count_value3 = row["count_value3"] != DBNull.Value ? Convert.ToDouble(row["count_value3"]) : 0.0,
                    };
                    sensorDeviceDataList.Add(sensorDeviceData);
                }
                if (sensorDeviceDataList.Count > 0)
                {
                    ShowSensorChartData(sensorEntity.SensorType, sensorDeviceDataList);
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }

        private void ShowSensorChartData(int sensorType ,List<SensorDeviceData> sensorDeviceDataList)
        {
            try
            {
                ChartValues<DateTimePoint> chartValues1 = new ChartValues<DateTimePoint>();
                ChartValues<DateTimePoint> chartValues2 = new ChartValues<DateTimePoint>();
                ChartValues<DateTimePoint> chartValues3 = new ChartValues<DateTimePoint>();
                for (int index = 0; index < sensorDeviceDataList.Count; index++)
                {
                    SensorDeviceData sensorDeviceData = sensorDeviceDataList[index];
                    if (sensorDeviceData != null)
                    {
                        chartValues1.Add(new DateTimePoint(sensorDeviceData.collect_time, sensorDeviceData.count_value1));
                        if (sensorDeviceData.sensor_type == 3)
                        {
                            chartValues2.Add(new DateTimePoint(sensorDeviceData.collect_time, sensorDeviceData.count_value2));
                            chartValues3.Add(new DateTimePoint(sensorDeviceData.collect_time, sensorDeviceData.count_value3));
                        }
                    }
                }
                if(sensorType == 3)
                {
                    InitChartConfig(chartValues1, chartValues2, chartValues3);
                }
                else
                {
                    InitChartConfig(chartValues1);
                }
                
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }

        private void InitChartConfig()
        {
            string title = "值";
            try
            {
                if (OscChart.InvokeRequired)
                {
                    OscChart.Invoke(new System.Action(() =>
                    {
                        OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                        {
                            //绑定C#代码中的实际数据值。
                            Values = InitChartValuesEmptyData(),
                            //坐标轴名称。
                            Title = title,
                            //曲线下方填充颜色。Transparent透明，即不填充。
                            Fill = System.Windows.Media.Brushes.Transparent,
                            //曲线颜色。
                            //Stroke = System.Windows.Media.Brushes.Transparent,
                            //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                            PointGeometry = DefaultGeometries.Circle,
                            //数据点形状的大小。
                            PointGeometrySize = 15,
                            //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                            LineSmoothness = 1,
                            //曲线粗细程度，越大越粗。
                            StrokeThickness = 4,
                            //设置点的颜色
                            PointForeground = System.Windows.Media.Brushes.Blue,
                            //曲线对应Y坐标
                            ScalesYAt = 0
                        });
                        OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                        {
                            //Title = "时间",
                            //设置X轴的最小值为当前时间减去60秒的Ticks，最大值为当前时间加上60秒的Ticks
                            //最小值，不写则会根据数据自动变化。
                            //MinValue = this.xTimes - this.xCount
                            //MinValue = DateTime.Now.AddSeconds(-60).Ticks,
                            //最大值，不写则会根据数据自动变化。
                            //MaxValue = this.xTimes,
                            //MaxValue = DateTime.Now.AddSeconds(60).Ticks,
                            //设置单位宽度为1秒
                            MinWidth = TimeSpan.FromSeconds(1).Ticks,
                            //设置最小步长为1秒，确保每秒都有刻度
                            MinRange = TimeSpan.FromSeconds(1).Ticks,
                            //字体大小
                            FontSize = 12,
                            DisableAnimations = true,
                            Foreground = System.Windows.Media.Brushes.Black,
                            // 标签格式，如把数值格式化为时间，设置标签格式化器，以便每个刻度都显示为时间
                            //LabelFormatter = value => new DateTime((long)value).ToString("HH:mm:ss.ff"),
                            //LabelFormatter = value => value.ToString(),
                            //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                            LabelFormatter = value => (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((long)value)).ToString("HH:mm:ss.fff"),
                            //网格线，IsEnabled决定是否显示，Step为网格一格的大小，不写则自动。
                            //Separator = new Separator
                            //{
                            //    Step = 1,
                            //    IsEnabled = true
                            //}
                        });
                        OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                        {
                            //坐标轴名称。
                            Title = title,
                            //字体大小
                            FontSize = 12,
                            //名称和刻度的颜色。
                            Foreground = System.Windows.Media.Brushes.DodgerBlue,
                            //坐标轴位置。
                            Position = AxisPosition.LeftBottom
                        });
                    }));
                }
                else
                {
                    OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                    {
                        //绑定C#代码中的实际数据值。
                        Values = InitChartValuesEmptyData(),
                        //坐标轴名称。
                        Title = title,
                        //曲线下方填充颜色。Transparent透明，即不填充。
                        Fill = System.Windows.Media.Brushes.Transparent,
                        //曲线颜色。
                        //Stroke = System.Windows.Media.Brushes.Transparent,
                        //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                        PointGeometry = DefaultGeometries.Circle,
                        //数据点形状的大小。
                        PointGeometrySize = 15,
                        //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                        LineSmoothness = 1,
                        //曲线粗细程度，越大越粗。
                        StrokeThickness = 4,
                        //设置点的颜色
                        PointForeground = System.Windows.Media.Brushes.Blue,
                        //曲线对应Y坐标
                        ScalesYAt = 0
                    });
                    OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                    {
                        //Title = "时间",
                        //设置X轴的最小值为当前时间减去60秒的Ticks，最大值为当前时间加上60秒的Ticks
                        //最小值，不写则会根据数据自动变化。
                        //MinValue = this.xTimes - this.xCount
                        //MinValue = DateTime.Now.AddSeconds(-60).Ticks,
                        //最大值，不写则会根据数据自动变化。
                        //MaxValue = this.xTimes,
                        //MaxValue = DateTime.Now.AddSeconds(60).Ticks,
                        //设置单位宽度为1秒
                        MinWidth = TimeSpan.FromSeconds(1).Ticks,
                        //设置最小步长为1秒，确保每秒都有刻度
                        MinRange = TimeSpan.FromSeconds(1).Ticks,
                        //字体大小
                        FontSize = 12,
                        DisableAnimations = true,
                        Foreground = System.Windows.Media.Brushes.Black,
                        // 标签格式，如把数值格式化为时间，设置标签格式化器，以便每个刻度都显示为时间
                        //LabelFormatter = value => new DateTime((long)value).ToString("HH:mm:ss.ff"),
                        //LabelFormatter = value => value.ToString(),
                        //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                        LabelFormatter = value => (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((long)value)).ToString("HH:mm:ss.fff"),
                        //网格线，IsEnabled决定是否显示，Step为网格一格的大小，不写则自动。
                        //Separator = new Separator
                        //{
                        //    Step = 1,
                        //    IsEnabled = true
                        //}
                    });
                    OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                    {
                        //坐标轴名称。
                        Title = title,
                        //字体大小
                        FontSize = 12,
                        //名称和刻度的颜色。
                        Foreground = System.Windows.Media.Brushes.DodgerBlue,
                        //坐标轴位置。
                        Position = AxisPosition.LeftBottom
                    });
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            finally
            {
            }
        }


        private void InitChartConfig(ChartValues<DateTimePoint> chartValues)
        {
            try
            {
                // 假设你在非UI线程上
                if (OscChart.InvokeRequired)
                {
                    OscChart.Invoke(new System.Action(() =>
                    {
                        OscChart.Series.Clear();
                        OscChart.AxisX.Clear();
                        OscChart.AxisY.Clear();
                    }));
                }
                else
                {
                    OscChart.Series.Clear();
                    OscChart.AxisX.Clear();
                    OscChart.AxisY.Clear();
                }
                string title = "值";
                // 假设你在非UI线程上
                if (OscChart.InvokeRequired)
                {
                    OscChart.Invoke(new Action(() =>
                    {
                        OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                        {
                            //绑定C#代码中的实际数据值。
                            Values = chartValues,
                            //坐标轴名称。
                            Title = title,
                            //曲线下方填充颜色。Transparent透明，即不填充。
                            Fill = System.Windows.Media.Brushes.Transparent,
                            //曲线颜色。
                            //Stroke = System.Windows.Media.Brushes.Transparent,
                            //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                            PointGeometry = DefaultGeometries.Circle,
                            //数据点形状的大小。
                            PointGeometrySize = 15,
                            //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                            LineSmoothness = 1,
                            //曲线粗细程度，越大越粗。
                            StrokeThickness = 4,
                            //设置点的颜色
                            PointForeground = System.Windows.Media.Brushes.Blue,
                            //曲线对应Y坐标
                            ScalesYAt = 0
                        });
                        OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                        {
                            //Title = "时间",
                            //设置X轴的最小值为当前时间减去60秒的Ticks，最大值为当前时间加上60秒的Ticks
                            //最小值，不写则会根据数据自动变化。
                            //MinValue = this.xTimes - this.xCount
                            //MinValue = DateTime.Now.AddSeconds(-60).Ticks,
                            //最大值，不写则会根据数据自动变化。
                            //MaxValue = this.xTimes,
                            //MaxValue = DateTime.Now.AddSeconds(60).Ticks,
                            //设置单位宽度为1秒
                            MinWidth = TimeSpan.FromSeconds(1).Ticks,
                            //设置最小步长为1秒，确保每秒都有刻度
                            MinRange = TimeSpan.FromSeconds(1).Ticks,
                            //字体大小
                            FontSize = 12,
                            DisableAnimations = true,
                            Foreground = System.Windows.Media.Brushes.Black,
                            // 标签格式，如把数值格式化为时间，设置标签格式化器，以便每个刻度都显示为时间
                            //LabelFormatter = value => new DateTime((long)value).ToString("HH:mm:ss.ff"),
                            //LabelFormatter = value => value.ToString(),
                            //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                            LabelFormatter = value => (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((long)value)).ToString("HH:mm:ss.fff"),
                            //网格线，IsEnabled决定是否显示，Step为网格一格的大小，不写则自动。
                            //Separator = new Separator
                            //{
                            //    Step = 1,
                            //    IsEnabled = true
                            //}
                        });
                        OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                        {
                            //坐标轴名称。
                            Title = title,
                            //字体大小
                            FontSize = 12,
                            //名称和刻度的颜色。
                            Foreground = System.Windows.Media.Brushes.DodgerBlue,
                            //坐标轴位置。
                            Position = AxisPosition.LeftBottom
                        });
                    }));
                }
                else
                {
                    OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                    {
                        //绑定C#代码中的实际数据值。
                        Values = chartValues,
                        //坐标轴名称。
                        Title = title,
                        //曲线下方填充颜色。Transparent透明，即不填充。
                        Fill = System.Windows.Media.Brushes.Transparent,
                        //曲线颜色。
                        //Stroke = System.Windows.Media.Brushes.Transparent,
                        //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                        PointGeometry = DefaultGeometries.Circle,
                        //数据点形状的大小。
                        PointGeometrySize = 15,
                        //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                        LineSmoothness = 1,
                        //曲线粗细程度，越大越粗。
                        StrokeThickness = 4,
                        //设置点的颜色
                        PointForeground = System.Windows.Media.Brushes.Blue,
                        //曲线对应Y坐标
                        ScalesYAt = 0
                    });
                    OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                    {
                        //Title = "时间",
                        //设置X轴的最小值为当前时间减去60秒的Ticks，最大值为当前时间加上60秒的Ticks
                        //最小值，不写则会根据数据自动变化。
                        //MinValue = this.xTimes - this.xCount
                        //MinValue = DateTime.Now.AddSeconds(-60).Ticks,
                        //最大值，不写则会根据数据自动变化。
                        //MaxValue = this.xTimes,
                        //MaxValue = DateTime.Now.AddSeconds(60).Ticks,
                        //设置单位宽度为1秒
                        MinWidth = TimeSpan.FromSeconds(1).Ticks,
                        //设置最小步长为1秒，确保每秒都有刻度
                        MinRange = TimeSpan.FromSeconds(1).Ticks,
                        //字体大小
                        FontSize = 12,
                        DisableAnimations = true,
                        Foreground = System.Windows.Media.Brushes.Black,
                        // 标签格式，如把数值格式化为时间，设置标签格式化器，以便每个刻度都显示为时间
                        //LabelFormatter = value => new DateTime((long)value).ToString("HH:mm:ss.ff"),
                        //LabelFormatter = value => value.ToString(),
                        //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                        LabelFormatter = value => (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((long)value)).ToString("HH:mm:ss.fff"),
                        //网格线，IsEnabled决定是否显示，Step为网格一格的大小，不写则自动。
                        //Separator = new Separator
                        //{
                        //    Step = 1,
                        //    IsEnabled = true
                        //}
                    });
                    OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                    {
                        //坐标轴名称。
                        Title = title,
                        //字体大小
                        FontSize = 12,
                        //名称和刻度的颜色。
                        Foreground = System.Windows.Media.Brushes.DodgerBlue,
                        //坐标轴位置。
                        Position = AxisPosition.LeftBottom
                    });
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }

        private void InitChartConfig(ChartValues<DateTimePoint> chartValues1, ChartValues<DateTimePoint> chartValues2, ChartValues<DateTimePoint> chartValues3)
        {
            try
            {
                // 假设你在非UI线程上
                if (OscChart.InvokeRequired)
                {
                    OscChart.Invoke(new System.Action(() =>
                    {
                        OscChart.Series.Clear();
                        OscChart.AxisX.Clear();
                        OscChart.AxisY.Clear();
                    }));
                }
                else
                {
                    OscChart.Series.Clear();
                    OscChart.AxisX.Clear();
                    OscChart.AxisY.Clear();
                }
                string title = "值";
                // 假设你在非UI线程上
                if (OscChart.InvokeRequired)
                {
                    OscChart.Invoke(new Action(() =>
                    {
                        OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                        {
                            Values = chartValues1,
                            //坐标轴名称。
                            Title = title,
                            //曲线下方填充颜色。Transparent透明，即不填充。
                            Fill = System.Windows.Media.Brushes.Transparent,
                            //曲线颜色。
                            //Stroke = System.Windows.Media.Brushes.Transparent,
                            //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                            PointGeometry = DefaultGeometries.Circle,
                            //数据点形状的大小。
                            PointGeometrySize = 15,
                            //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                            LineSmoothness = 1,
                            //曲线粗细程度，越大越粗。
                            StrokeThickness = 4,
                            //设置点的颜色
                            PointForeground = System.Windows.Media.Brushes.Blue,
                            //曲线对应Y坐标
                            ScalesYAt = 0
                        });
                        OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                        {
                            Values = chartValues2,
                            //坐标轴名称。
                            Title = title,
                            //曲线下方填充颜色。Transparent透明，即不填充。
                            Fill = System.Windows.Media.Brushes.Transparent,
                            //曲线颜色。
                            //Stroke = System.Windows.Media.Brushes.Transparent,
                            //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                            PointGeometry = DefaultGeometries.Circle,
                            //数据点形状的大小。
                            PointGeometrySize = 15,
                            //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                            LineSmoothness = 1,
                            //曲线粗细程度，越大越粗。
                            StrokeThickness = 4,
                            //设置点的颜色
                            PointForeground = System.Windows.Media.Brushes.Blue,
                            //曲线对应Y坐标
                            ScalesYAt = 0
                        });
                        OscChart.Series.Add(new LiveCharts.Wpf.LineSeries
                        {
                            Values = chartValues3,
                            //坐标轴名称。
                            Title = title,
                            //曲线下方填充颜色。Transparent透明，即不填充。
                            Fill = System.Windows.Media.Brushes.Transparent,
                            //曲线颜色。
                            //Stroke = System.Windows.Media.Brushes.Transparent,
                            //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                            PointGeometry = DefaultGeometries.Circle,
                            //数据点形状的大小。
                            PointGeometrySize = 15,
                            //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                            LineSmoothness = 1,
                            //曲线粗细程度，越大越粗。
                            StrokeThickness = 4,
                            //设置点的颜色
                            PointForeground = System.Windows.Media.Brushes.Blue,
                            //曲线对应Y坐标
                            ScalesYAt = 0
                        });
                        OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                        {
                            //Title = "时间",
                            //设置X轴的最小值为当前时间减去60秒的Ticks，最大值为当前时间加上60秒的Ticks
                            //最小值，不写则会根据数据自动变化。
                            //MinValue = this.xTimes - this.xCount
                            //MinValue = DateTime.Now.AddSeconds(-60).Ticks,
                            //最大值，不写则会根据数据自动变化。
                            //MaxValue = this.xTimes,
                            //MaxValue = DateTime.Now.AddSeconds(60).Ticks,
                            //设置单位宽度为1秒
                            MinWidth = TimeSpan.FromSeconds(1).Ticks,
                            //设置最小步长为1秒，确保每秒都有刻度
                            MinRange = TimeSpan.FromSeconds(1).Ticks,
                            //字体大小
                            FontSize = 12,
                            DisableAnimations = true,
                            Foreground = System.Windows.Media.Brushes.Black,
                            // 标签格式，如把数值格式化为时间，设置标签格式化器，以便每个刻度都显示为时间
                            //LabelFormatter = value => new DateTime((long)value).ToString("HH:mm:ss.ff"),
                            //LabelFormatter = value => value.ToString(),
                            //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                            LabelFormatter = value => (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((long)value)).ToString("HH:mm:ss.fff"),
                            //网格线，IsEnabled决定是否显示，Step为网格一格的大小，不写则自动。
                            //Separator = new Separator
                            //{
                            //    Step = 1,
                            //    IsEnabled = true
                            //}
                        });
                        OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                        {
                            //坐标轴名称。
                            Title = title,
                            //字体大小
                            FontSize = 12,
                            //名称和刻度的颜色。
                            Foreground = System.Windows.Media.Brushes.DodgerBlue,
                            //坐标轴位置。
                            Position = AxisPosition.LeftBottom
                        });
                    }));
                }
                else
                {
                    OscChart.Series.Add(new LiveCharts.Wpf.StackedAreaSeries
                    {
                        Values = chartValues1,
                        //坐标轴名称。
                        Title = title,
                        //曲线下方填充颜色。Transparent透明，即不填充。
                        Fill = System.Windows.Media.Brushes.Transparent,
                        //曲线颜色。
                        //Stroke = System.Windows.Media.Brushes.Transparent,
                        //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                        PointGeometry = DefaultGeometries.Circle,
                        //数据点形状的大小。
                        PointGeometrySize = 15,
                        //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                        LineSmoothness = 1,
                        //曲线粗细程度，越大越粗。
                        StrokeThickness = 4,
                        //设置点的颜色
                        PointForeground = System.Windows.Media.Brushes.Blue,
                        //曲线对应Y坐标
                        ScalesYAt = 0
                    });
                    OscChart.Series.Add(new LiveCharts.Wpf.StackedAreaSeries
                    {
                        Values = chartValues2,
                        //坐标轴名称。
                        Title = title,
                        //曲线下方填充颜色。Transparent透明，即不填充。
                        Fill = System.Windows.Media.Brushes.Transparent,
                        //曲线颜色。
                        //Stroke = System.Windows.Media.Brushes.Transparent,
                        //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                        PointGeometry = DefaultGeometries.Circle,
                        //数据点形状的大小。
                        PointGeometrySize = 15,
                        //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                        LineSmoothness = 1,
                        //曲线粗细程度，越大越粗。
                        StrokeThickness = 4,
                        //设置点的颜色
                        PointForeground = System.Windows.Media.Brushes.Blue,
                        //曲线对应Y坐标
                        ScalesYAt = 0
                    });
                    OscChart.Series.Add(new LiveCharts.Wpf.StackedAreaSeries
                    {
                        Values = chartValues3,
                        //坐标轴名称。
                        Title = title,
                        //曲线下方填充颜色。Transparent透明，即不填充。
                        Fill = System.Windows.Media.Brushes.Transparent,
                        //曲线颜色。
                        //Stroke = System.Windows.Media.Brushes.Transparent,
                        //数据点的外观。{x:Null}即不标出，只显示曲线。{x:Static lvc:DefaultGeometries.Circle} 则将数据点用圆形标出。形状有 Circle、Cross、Diamond、Square、Triangle可选。
                        PointGeometry = DefaultGeometries.Circle,
                        //数据点形状的大小。
                        PointGeometrySize = 15,
                        //曲线是否圆滑。如为 1则圆滑曲线，为 0则不圆滑，为折线。
                        LineSmoothness = 1,
                        //曲线粗细程度，越大越粗。
                        StrokeThickness = 4,
                        //设置点的颜色
                        PointForeground = System.Windows.Media.Brushes.Blue,
                        //曲线对应Y坐标
                        ScalesYAt = 0
                    });
                    OscChart.AxisX.Add(new LiveCharts.Wpf.Axis
                    {
                        //Title = "时间",
                        //设置X轴的最小值为当前时间减去60秒的Ticks，最大值为当前时间加上60秒的Ticks
                        //最小值，不写则会根据数据自动变化。
                        //MinValue = this.xTimes - this.xCount
                        //MinValue = DateTime.Now.AddSeconds(-60).Ticks,
                        //最大值，不写则会根据数据自动变化。
                        //MaxValue = this.xTimes,
                        //MaxValue = DateTime.Now.AddSeconds(60).Ticks,
                        //设置单位宽度为1秒
                        MinWidth = TimeSpan.FromSeconds(1).Ticks,
                        //设置最小步长为1秒，确保每秒都有刻度
                        MinRange = TimeSpan.FromSeconds(1).Ticks,
                        //字体大小
                        FontSize = 12,
                        DisableAnimations = true,
                        Foreground = System.Windows.Media.Brushes.Black,
                        // 标签格式，如把数值格式化为时间，设置标签格式化器，以便每个刻度都显示为时间
                        //LabelFormatter = value => new DateTime((long)value).ToString("HH:mm:ss.ff"),
                        //LabelFormatter = value => value.ToString(),
                        //LabelFormatter = value => new System.DateTime(System.DateTime.Now.Ticks - (long)(this.xNumber - (long)value) * this.intervalTime * 10000).ToString("mm:ss"),
                        LabelFormatter = value => (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds((long)value)).ToString("HH:mm:ss.fff"),
                        //网格线，IsEnabled决定是否显示，Step为网格一格的大小，不写则自动。
                        //Separator = new Separator
                        //{
                        //    Step = 1,
                        //    IsEnabled = true
                        //}
                    });
                    OscChart.AxisY.Add(new LiveCharts.Wpf.Axis
                    {
                        //坐标轴名称。
                        Title = title,
                        //字体大小
                        FontSize = 12,
                        //名称和刻度的颜色。
                        Foreground = System.Windows.Media.Brushes.DodgerBlue,
                        //坐标轴位置。
                        Position = AxisPosition.LeftBottom
                    });
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }


        private void btnExport_Click(object sender, EventArgs e)
        {
            // 创建Excel应用程序实例
            //this.excelApp = new Excel.Application();
            if (this.excelApp == null)
            {
                CreateExcelDataFile();

            }
            if (this.workbook == null)
            {
                MessageBox.Show("无法打开 Workbook 对象，请确认 Excel 文件是否正常");
                return;

            }

            DateTime dt = DateTime.Now; // 获取今天的日期
            string date = dt.Year.ToString("D4") + dt.Month.ToString("D2") + dt.Day.ToString("D2") + dt.Hour.ToString("D2") + dt.Minute.ToString("D2") + dt.Second.ToString("D2");
            Excel.Workbooks workbooks = this.excelApp.Workbooks;
            string filePath;
            if (this.waveFilePath == "")
            {
                filePath = AppDomain.CurrentDomain.BaseDirectory + this.waveFileName + @"-" + date + @".xlsx";
            }
            else
            {
                filePath = this.waveFilePath + this.waveFileName + @"-" + date + @".xlsx";
            }
            try
            {
                if (File.Exists(filePath))
                {
                    this.workbook = workbooks.Add(filePath); //加载模板
                }
                else
                {
                    File.Copy(AppDomain.CurrentDomain.BaseDirectory + this.waveFileName + @".xlsx", filePath, true);
                    this.workbook = workbooks.Add(filePath); //加载模板
                }
            }
            catch (Exception ex)
            {
                bool isUnlocked = FileUnlocker.UnlockFile(filePath);
                if (isUnlocked)
                {
                    this.workbook = workbooks.Add(filePath); //加载模板
                }
                else
                {
                    MessageBox.Show("存储 Excel 文件时出错,文件可能正被打开！\n" + ex.Message);
                    log.Error(ex.Message);
                    return;
                }
            }
            if (this.workbook == null)
            {
                MessageBox.Show("无法打开 Workbook 对象，请确认 Excel 文件是否正常");
                return;
            }

            if (!this.waveFileNameDate.Equals(date))
            {
                this.waveFileNameDate = date;
            }

            Excel.Sheets sheets = workbook.Sheets;
            Excel.Worksheet worksheet = (Excel.Worksheet)sheets.get_Item(1); //第一个工作薄。
            if (worksheet == null)
            {
                MessageBox.Show("无法打开 Worksheet 对象，请确认 Excel 文件是否正常");
                return; //工作薄中没有工作表.
            }

            int columnIndex = 1; // A列的索引是1
            int columnCount = CountColumnValues(worksheet, columnIndex);

            if ((sensorDeviceDataList != null) && (sensorDeviceDataList.Count > 0))
            {
                //写入数值
                for (int i = 0; i < sensorDeviceDataList.Count; i++)
                {
                    SensorDeviceData sensorDeviceData = sensorDeviceDataList.Get(i);
                    //写入内容
                    worksheet.Cells[columnCount + 1 + i, 1] = sensorDeviceData.id;
                    worksheet.Cells[columnCount + 1 + i, 2] = sensorDeviceData.uid;
                    worksheet.Cells[columnCount + 1 + i, 3] = sensorDeviceData.device_id;
                    worksheet.Cells[columnCount + 1 + i, 4] = sensorDeviceData.collect_datetime;
                    worksheet.Cells[columnCount + 1 + i, 5] = sensorDeviceData.collect_time;
                    worksheet.Cells[columnCount + 1 + i, 6] = sensorDeviceData.channel_id;
                    worksheet.Cells[columnCount + 1 + i, 7] = sensorDeviceData.sensor_id;
                    worksheet.Cells[columnCount + 1 + i, 8] = sensorDeviceData.sensor_name;
                    worksheet.Cells[columnCount + 1 + i, 9] = sensorDeviceData.sensor_type;
                    worksheet.Cells[columnCount + 1 + i, 10] = sensorDeviceData.sensor_count;
                    worksheet.Cells[columnCount + 1 + i, 11] = sensorDeviceData.sensor_index;
                    worksheet.Cells[columnCount + 1 + i, 12] = sensorDeviceData.wave_length1;
                    worksheet.Cells[columnCount + 1 + i, 13] = sensorDeviceData.wave_length2;
                    worksheet.Cells[columnCount + 1 + i, 14] = sensorDeviceData.wave_length3;
                    worksheet.Cells[columnCount + 1 + i, 15] = sensorDeviceData.count_value1;
                    worksheet.Cells[columnCount + 1 + i, 16] = sensorDeviceData.count_value2;
                    worksheet.Cells[columnCount + 1 + i, 17] = sensorDeviceData.count_value3;
                }
                worksheet.Columns.EntireColumn.AutoFit();//列宽自适应
            }
            
            try
            {
                this.workbook.Saved = true;
                this.workbook.SaveAs(filePath);
            }
            catch (Exception ex)
            {
                bool isUnlocked = FileUnlocker.UnlockFile(filePath);
                if (isUnlocked)
                {
                    this.workbook.SaveAs(filePath);
                }
                else
                {
                    MessageBox.Show("存储 Excel 文件时出错,文件可能正被打开！\n" + ex.Message);
                    log.Error(ex.Message);
                    return;
                }
            }
            finally
            {
                if (this.excelApp != null)
                {
                    this.excelApp.DisplayAlerts = false;
                    if (this.workbook != null)
                    {
                        this.workbook.Close(false);
                        this.workbook = null;
                    }
                    this.excelApp.Quit();
                    this.excelApp = null;
                }
            }
            RecordUserOperation("导出历史记录 filePath="+filePath);
        }

        private void CreateExcelDataFile()
        {
            // 创建Excel应用程序实例
            this.excelApp = new Excel.Application();
            this.excelApp.Visible = false;
            this.excelApp.UserControl = true;
            this.excelApp.DisplayAlerts = false;

            DateTime dt = DateTime.Now;
            string date = dt.Year.ToString("D4") + dt.Month.ToString("D2") + dt.Day.ToString("D2") + dt.Hour.ToString("D2") + dt.Minute.ToString("D2") + dt.Second.ToString("D2");
            string filePath;
            if (waveFilePath == "")
            {
                filePath = AppDomain.CurrentDomain.BaseDirectory + waveFileName + @"-" + date + @".xlsx";
            }
            else
            {
                filePath = waveFilePath + waveFileName + @"-" + date + @".xlsx";
            }
            Excel.Workbooks workbooks = this.excelApp.Workbooks;
            try
            {
                if (!File.Exists(filePath))
                {
                    File.Copy(AppDomain.CurrentDomain.BaseDirectory + waveFileName + @".xlsx", filePath, true);
                }
                this.workbook = workbooks.Add(filePath); //加载模板
            }
            catch (Exception ex)
            {
                bool isUnlocked = FileUnlocker.UnlockFile(filePath);
                if (isUnlocked)
                {
                    this.workbook = workbooks.Add(filePath); //加载模板
                }
                else
                {
                    MessageBox.Show("存储 Excel 文件时出错,文件可能正被打开！\n" + ex.Message);
                    log.Error(ex.Message);
                    return;
                }
            }
            waveFileNameDate = date;
        }

        private int CountColumnValues(Excel.Worksheet worksheet, int columnIndex)
        {
            int valueCount = 0;
            try {
                Excel.Range usedRange = worksheet.UsedRange;
                // 获取列的范围
                Excel.Range columnRange = (Excel.Range)worksheet.Columns[columnIndex];
                int lastRow = columnRange.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell).Row;

                // 遍历列中的所有单元格
                for (int row = 1; row <= lastRow; row++)
                {
                    Excel.Range cell = (Excel.Range)worksheet.Cells[row, columnIndex];
                    if (cell.Value2 != null && !cell.Value2.ToString().Trim().Equals(""))
                    {
                        valueCount++;
                    }
                }
                System.Runtime.InteropServices.Marshal.ReleaseComObject(columnRange);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(usedRange);
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
            return valueCount;
        }


        public static long ToUnixTimestamp(DateTime dateTime)
        {
            return (long)Math.Floor((dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds);
        }

        public static long ToUnixTimestampMilliseconds(DateTime dateTime)
        {
            return (long)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }

        public void RecordUserOperation(string operation)
        {
            try
            {
                string userName = LoginForm.username;
                string userIp = "127.0.0.1";
                long recordTime = ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeMilliseconds(); ;
                MainForm.db.ExecuteSql(
                    MainForm.db.Insert("system_operation_content")
                        .SetColumn("UserName", userName)
                        .SetColumn("UserIP", userIp)
                        .SetColumn("RecordTime", recordTime)
                        .SetColumn("Operation", operation)
                        .ToSql());
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }

    }

    public class SensorDeviceData
    {
        public long id { get; set; }
        //采集UUID
        public string uid { get; set; }
        //采集设备ID
        public string device_id { get; set; }
        //采集时间
        public long collect_time { get; set; }
        //采集日期时间
        public string collect_datetime { get; set; }
        //通道ID
        public int channel_id { get; set; }
        //传感器ID
        public string sensor_id { get; set; }
        //传感器名称
        public string sensor_name { get; set; }
        //传感器类型
        public int sensor_type { get; set; }
        //传感器数量
        public int sensor_count { get; set; }
        //传感器索引
        public int sensor_index { get; set; }
        //光栅波长1
        public double wave_length1 { get; set; }
        //光栅波长2
        public double wave_length2 { get; set; }
        //光栅波长3
        public double wave_length3 { get; set; }
        //结果1
        public double count_value1 { get; set; }
        //结果2
        public double count_value2 { get; set; }
        //结果3
        public double count_value3 { get; set; }

        public override string ToString()
        {
            return id + ", "+ uid + ", " + device_id + ", " + collect_time + ", " + collect_datetime + ", " + channel_id + ", " + sensor_id + ", " + sensor_name + ", " + sensor_type + ", " + sensor_count + ", " + sensor_index
                + ", " + wave_length1 + ", " + wave_length2 + ", " + wave_length3 + ", " + count_value1 + ", " + count_value2 + ", " + count_value3;
        }

        public string[] ToArrayString()
        {
            string[] data = new String[]{
                                id.ToString(),uid.ToString(),device_id.ToString(),collect_time.ToString(),collect_datetime.ToString(),channel_id.ToString(),sensor_id.ToString(),sensor_name.ToString(),sensor_type.ToString(),sensor_count.ToString(),sensor_index.ToString(),
                                wave_length1.ToString(),wave_length2.ToString(),wave_length3.ToString(),count_value1.ToString(),count_value2.ToString(),count_value3.ToString()};
            return data;
        }
    }

}